﻿using System;
using System.Windows;
using System.Windows.Media;

namespace Expression.Samples.Physics {
	public static class MathEx {

		public static double InterpolateQuad(double percent, double min, double max) {
			return MathEx.Interpolate(percent, min, max, 0, 1);
		}

		public static double Interpolate(double percent, double min, double max, double easeIn, double easeOut) {
			double a = MathEx.WeightedAverage(0, easeIn, percent);
			double b = MathEx.WeightedAverage(easeIn, easeOut, percent);
			double c = MathEx.WeightedAverage(easeOut, 1, percent);
			double aa = MathEx.WeightedAverage(a, b, percent);
			double bb = MathEx.WeightedAverage(b, c, percent);

			return WeightedAverage(aa, bb, percent) * (max - min) + min;

		}

		private static double WeightedAverage(double a, double b, double t) {
			return (1 - t) * a + t * b;
		}

		public static double Log(double a, double newBase) {
			return Math.Log(a) / Math.Log(newBase);
		}

		public static double Clamp(double value, double min, double max) {
			return Math.Min(Math.Max(value, min), max);
		}

		public static int Clamp(int value, int min, int max) {
			return Math.Min(Math.Max(value, min), max);
		}

		public static double Rad2Deg(double r) {
			return r * 180.0 / Math.PI;
		}

		public static double Deg2Rad(double d) {
			return d * Math.PI / 180.0;
		}

		public static Vector Sub(this Point a, Point b) {
			return new Vector(a.X - b.X, a.Y - b.Y);
		}

		public static Vector Sub(this Point a, Vector b) {
			return new Vector(a.X - b.X, a.Y - b.Y);
		}

		public static Vector Add(this Point a, Point b) {
			return new Vector(a.X + b.X, a.Y + b.Y);
		}

		public static Vector Add(this Point a, Size b) {
			return new Vector(a.X + b.Width, a.Y + b.Height);
		}

		public static Vector Div(this Point a, double dividend) {
			return new Vector(a.X / dividend, a.Y / dividend);
		}

		public static Vector Mul(this Point a, double scalar) {
			return new Vector(a.X * scalar, a.Y * scalar);
		}

		public static Size Mul(this Size a, double scalar) {
			return new Size(a.Width * scalar, a.Height * scalar);
		}

		public static Size Div(this Size a, double scalar) {
			return new Size(a.Width / scalar, a.Height / scalar);
		}

		

		public static void Offset(this Rect rect, double offsetX, double offsetY) {
			rect.X += offsetX;
			rect.Y += offsetY;
		}

		public static bool Contains(this Rect rect, double x, double y) {
			if (((x >= rect.X) && ((x - rect.Width) <= rect.X)) && (y >= rect.Y)) {
				return ((y - rect.Height) <= rect.Y);
			}
			return false;
		}


		public static Matrix Invert(this Matrix value) {

			double inverseDeterminant = 1.0 / ((value.M11 * value.M22) - (value.M12 * value.M21));

			return new Matrix(value.M22 * inverseDeterminant, -value.M12 * inverseDeterminant, -value.M21 * inverseDeterminant, value.M11 * inverseDeterminant, ((value.M21 * value.OffsetY) - (value.OffsetX * value.M22)) * inverseDeterminant, ((value.OffsetX * value.M12) - (value.M11 * value.OffsetY)) * inverseDeterminant);
		}

	}
}
